#region COPYRIGHT
//--------------------------------------------------------------------------------
// <copyright file="RegionsCameraConstraint.cs" company="starLiGHT Entertainment Studios">
//    Copyright (c) 2007, 2008, 2009, 2010
//       Roland Rosenkranz (Glatzemann@email.de)
// </copyright>
// <license>
//   This file is part of starLiGHT.Render.
//
//   starLiGHT.Render is free software: you can redistribute it and/or modify
//   it under the terms of the GNU Lesser General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
//
//   starLiGHT.Core is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU Lesser General Public License for more details.
//
//   You should have received a copy of the GNU Lesser General Public License
//   along with starLiGHT.Render. If not, see http://www.gnu.org/licenses/.
//    
//   ADDITIONAL (commercial) LICENSES for starLiGHT.Render are available on request.
// </license>
// <version>
// **************[ starLiGHT.Engine SVN ]**********************
// * $Rev:: 620                   $:  Revision of last commit *
// * $Author:: unknown            $:  Author of last commit   *
// * $Date:: 2010-12-07 15:23:58 #$:  Date of last commit     *
// ************************************************************
// </version>
//--------------------------------------------------------------------------------
#endregion

namespace starLiGHT.Camera.TwoD
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Xna.Framework;

    #endregion

    public class RegionsCameraConstraint : ICameraConstraint
    {
        private CameraRegion lastRegion;
        private CameraRegion actualRegion;
        private List<CameraRegion> regions;

        public RegionsCameraConstraint()
        {
            this.regions = new List<CameraRegion>();
        }

        public CameraRegion LastRegion
        {
            get { return this.lastRegion; }
            internal set { this.lastRegion = value; }
        }

        public CameraRegion ActualRegion
        {
            get { return this.actualRegion; }
            internal set { this.actualRegion = value; }
        }

        public List<CameraRegion> Regions
        {
            get { return this.regions; }
            internal set { this.regions = value; }
        }

        public string Name
        {
            get { return "RegionsCameraConstraint"; }
        }

        public int SortOrder
        {
            get { throw new NotImplementedException(); }
        }

        public Vector2 UpdatePosition(GameTime gameTime, Camera2D camera, Vector2 newPosition)
        {
            if (this.regions == null)
            {
                return newPosition;
            }

            RectangleF oldBounds = camera.Bounds;
            float x = camera.Bounds.TopLeft.X;
            float y = camera.Bounds.TopLeft.Y;
            float x2 = camera.Bounds.BottomRight.X;
            float y2 = camera.Bounds.BottomRight.Y;

            foreach (CameraRegion region in this.regions)
            {
                if (region.Bounds.Contains(camera.Bounds.Center))
                {
                    if (region != this.actualRegion)
                    {
                        if (this.actualRegion == null)
                        {
                            region.LastActive = 0L;
                        }
                        else if (region != this.lastRegion)
                        {
                            region.LastActive = gameTime.TotalGameTime.Ticks;
                        }

                        this.lastRegion = this.actualRegion;
                    }

                    this.actualRegion = region;
                }
            }

            if (this.actualRegion != null)
            {
                float t = (gameTime.TotalGameTime.Ticks - this.actualRegion.LastActive) / 4000000f;
                if (this.lastRegion == null)
                {
                    t = 1f;
                }

                float factor = MathHelper.Clamp(t, 0f, 1f);
                factor *= factor;

                x = MathHelper.Lerp(x, Math.Max(this.actualRegion.MinX.GetValueOrDefault(x), x), factor);
                y = MathHelper.Lerp(y, Math.Max(this.actualRegion.MinY.GetValueOrDefault(y), y), factor);
                x2 = MathHelper.Lerp(x2, Math.Min(this.actualRegion.MaxX.GetValueOrDefault(x2), x2), factor);
                y2 = MathHelper.Lerp(y2, Math.Min(this.actualRegion.MaxY.GetValueOrDefault(y2), y2), factor);

                if (this.lastRegion != null)
                {
                    float factor2 = 1f - MathHelper.Clamp(t - 1f, 0f, 1f);
                    x = MathHelper.Lerp(x, Math.Max(this.lastRegion.MinX.GetValueOrDefault(x), x), factor2);
                    y = MathHelper.Lerp(y, Math.Max(this.lastRegion.MinY.GetValueOrDefault(y), y), factor2);
                    x2 = MathHelper.Lerp(x2, Math.Min(this.lastRegion.MaxX.GetValueOrDefault(x2), x2), factor2);
                    y2 = MathHelper.Lerp(y2, Math.Min(this.lastRegion.MaxY.GetValueOrDefault(y2), y2), factor2);

                    if (factor2 <= 0f)
                    {
                        this.lastRegion = null;
                    }
                }

                camera.Bounds = new RectangleF(x, y, x2 - x, y2 - y);
                ////camera.Bounds.TopLeft = new Vector2(x, y);
                ////camera.Bounds.BottomRight = new Vector2(x2, y2);
                newPosition += camera.Bounds.TopLeft - oldBounds.TopLeft;
                newPosition += camera.Bounds.BottomRight - oldBounds.BottomRight;
            }

            return newPosition.Round();

            ////if (actualRegion == null)
            ////{
            ////    camera.ViewportPosition = new Vector2(MathHelper.Clamp(camera.ViewportPosition.X, cameraBounds.TopLeft.X, viewportOffset.X),
            ////                                   MathHelper.Clamp(camera.ViewportPosition.Y, cameraBounds.TopLeft.Y, viewportOffset.Y));
            ////}
        }
    }
}